from django.db import models
from django.apps import apps
from django.utils import timezone
from datetime import timedelta
from django.core.exceptions import ObjectDoesNotExist
from django.core.validators import MinLengthValidator, MaxLengthValidator
from zy_eval.models import EvalList
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver


class TeacherInfo(models.Model):
    """
    教师信息表
    """

    GENDER_CHOICES = [
        ("男", "男"),
        ("女", "女"),
        ("未知", "未知"),
    ]

    teacher_id = models.CharField(
        primary_key=True, max_length=20, unique=True, verbose_name="教师工号"
    )
    name = models.CharField(max_length=20, verbose_name="姓名")
    age = models.IntegerField(verbose_name="年龄", default=0)
    gender = models.CharField(
        max_length=2, verbose_name="性别", choices=GENDER_CHOICES, default="未知"
    )
    id_card = models.CharField(
        max_length=18,
        verbose_name="身份证号",
        unique=True,
        validators=[
            MinLengthValidator(18, message="身份证号长度为18位"),
            MaxLengthValidator(18, message="身份证号长度为18位"),
        ],
    )
    tel = models.CharField(max_length=11, verbose_name="联系电话", default=00000000000)
    course_count = models.IntegerField(verbose_name="课程数量", default=0)
    eval_count = models.IntegerField(verbose_name="被评测量", default=0)
    score = models.FloatField(verbose_name="评测分数", default=0)

    class Meta:
        verbose_name_plural = "教师信息"
        verbose_name = "教师信息"
        db_table = "zy_teacher"

    def update_age_gender(self):
        """
        更新年龄、性别
        """
        if self.id_card:
            try:
                birth = str(self.id_card)[6:14]
                today = timezone.now().date()
                birth_date = timezone.datetime.strptime(birth, "%Y%m%d").date()
                age = (
                    today.year
                    - birth_date.year
                    - ((today.month, today.day) < (birth_date.month, birth_date.day))
                )
                self.gender = "男" if int(self.id_card[-2]) % 2 == 1 else "女"
                self.age = age
            except (Exception, ValueError) as e:
                print("Invalid date format: ", e)
                return

    def update_course_count(self):
        """
        更新课程数量
        """
        self.course_count = ClassCourse.objects.filter(
            teacher_id=self.teacher_id
        ).count()

    def update_eval_count(self):
        """
        更新被评测量
        """
        self.eval_count = EvalList.objects.filter(
            teacher_id=self.teacher_id,
            eval_date__gte=timezone.now() - timedelta(days=90),
        ).count()

    def update_score(self):
        """
        更新评测分数
        """
        temp = EvalList.objects.filter(
            teacher_id=self.teacher_id,
            eval_date__gte=timezone.now() - timedelta(days=90),
        ).aggregate(models.Avg("score"))
        if temp["score__avg"]:
            self.score = temp["score__avg"]
        else:
            self.score = 0

    def save(self, *args, **kwargs):
        self.update_age_gender()
        self.update_course_count()
        self.update_eval_count()
        self.update_score()
        super(TeacherInfo, self).save(*args, **kwargs)

    def __str__(self):
        self.save()
        return self.name


class CourseInfo(models.Model):
    """
    课程信息表
    """

    course_id = models.AutoField(primary_key=True, verbose_name="课程编号")
    course_name = models.CharField(max_length=50, verbose_name="课程名称")
    credit = models.IntegerField(verbose_name="学分", default=0)

    class Meta:
        verbose_name_plural = "课程信息"
        verbose_name = "课程信息"
        db_table = "zy_course"

    def __str__(self):
        return self.course_name


class ClassInfo(models.Model):
    """
    班级信息表
    """

    class_id = models.AutoField(primary_key=True, verbose_name="班级编号")
    class_name = models.CharField(max_length=20, verbose_name="班级名称")
    grade = models.CharField(max_length=10, verbose_name="年级", default="1945级")
    class_header_id = models.ForeignKey(
        TeacherInfo,
        on_delete=models.PROTECT,
        verbose_name="班主任工号",
        default=None,
        blank=True,
    )
    class_header = models.CharField(
        max_length=20, verbose_name="班主任姓名", default=""
    )
    course_count = models.IntegerField(verbose_name="课程数量", default=0)
    student_count = models.IntegerField(verbose_name="学生数量", default=0)
    is_eval = models.BooleanField(verbose_name="评测开启", default=False)
    eval_count = models.IntegerField(verbose_name="已评测量", default=0)
    remain = models.IntegerField(verbose_name="剩余需评测量", default=0)

    class Meta:
        verbose_name_plural = "班级信息"
        verbose_name = "班级信息"
        db_table = "zy_class"

    def update_course_count(self):
        """
        更新课程数量
        """
        self.course_count = ClassCourse.objects.filter(class_id=self.class_id).count()
        # self.save()

    def update_student_count(self):
        """
        更新学生数量
        """
        self.student_count = StudentInfo.objects.filter(class_id=self.class_id).count()
        # self.save()

    def update_class_header(self):
        """
        更新班主任工号或姓名
        """
        try:
            if not self.class_header_id and self.class_header != "":
                self.class_header_id = TeacherInfo.objects.get(
                    name=self.class_header
                ).teacher_id
                # self.save()
            elif self.class_header_id and self.class_header == "":
                self.class_header = TeacherInfo.objects.get(
                    teacher_id=self.class_header_id.teacher_id
                ).name
                # self.save()
            elif self.class_header_id:
                self.class_header = TeacherInfo.objects.get(
                    teacher_id=self.class_header_id.teacher_id
                ).name
                # self.save()
            elif not self.class_header_id and self.class_header == "":
                print("班主任姓名或工号未填写")
        except ObjectDoesNotExist:
            print("班主任姓名或工号不存在")

    def update_eval_count(self):
        """
        更新评测量
        """
        self.eval_count = temp = EvalList.objects.filter(
            class_id=self.class_id,
            eval_date__gte=timezone.now() - timedelta(days=90),
        ).count()
        self.remain = self.course_count * self.student_count - temp
        # self.save()

    def save(self, *args, **kwargs):
        self.update_course_count()
        self.update_student_count()
        self.update_eval_count()
        self.update_class_header()
        super(ClassInfo, self).save(*args, **kwargs)

    def __str__(self):
        self.save()
        return self.class_name


class ClassCourse(models.Model):
    """
    班级课程表
    """

    class_course_id = models.AutoField(primary_key=True, verbose_name="班级课程编号")
    class_id = models.ForeignKey(
        ClassInfo, on_delete=models.PROTECT, verbose_name="班级id", default=None
    )
    class_name = models.CharField(max_length=20, verbose_name="班级名称", default="")
    course_id = models.ForeignKey(
        CourseInfo, on_delete=models.PROTECT, verbose_name="课程id", default=None
    )
    course_name = models.CharField(max_length=50, verbose_name="课程名称", default="")
    teacher_id = models.ForeignKey(
        TeacherInfo, on_delete=models.PROTECT, verbose_name="教师id", default=None
    )
    teacher_name = models.CharField(max_length=20, verbose_name="教师姓名", default="")

    class Meta:
        verbose_name_plural = "班级课程"
        verbose_name = "班级课程"
        db_table = "zy_class_course"

    def update_class_name(self):
        """
        更新班级名称
        """
        try:
            if self.class_id and self.class_name == "":
                self.class_name = ClassInfo.objects.get(
                    class_id=self.class_id.class_id
                ).class_name
                # self.save()
            elif not self.class_id and self.class_name != "":
                self.class_id = ClassInfo.objects.get(
                    class_name=self.class_name
                ).class_id
                # self.save()
            elif self.class_id:
                self.class_name = ClassInfo.objects.get(
                    class_id=self.class_id.class_id
                ).class_name
                # self.save()
            elif not self.class_id and self.class_name == "":
                print("班级ID或名称未填写")
        except ObjectDoesNotExist:
            print("班级ID或名称不存在")

    def update_course_name(self):
        """
        更新课程名称
        """
        try:
            if self.course_id and self.course_name == "":
                self.course_name = CourseInfo.objects.get(
                    course_id=self.course_id.course_id
                ).course_name
                # self.save()
            elif not self.course_id and self.course_name != "":
                self.course_id = CourseInfo.objects.get(
                    course_name=self.course_name
                ).course_id
                # self.save()
            elif self.course_id:
                self.course_name = CourseInfo.objects.get(
                    course_id=self.course_id.course_id
                ).course_name
                # self.save()
            elif not self.course_id and self.course_name == "":
                print("课程ID或名称未填写")
        except ObjectDoesNotExist:
            print("课程ID或名称不存在")

    def update_teacher_name(self):
        """
        更新教师姓名
        """
        try:
            if self.teacher_id and self.teacher_name == "":
                self.teacher_name = TeacherInfo.objects.get(
                    teacher_id=self.teacher_id.teacher_id
                ).name
                # self.save()
            elif not self.teacher_id and self.teacher_name != "":
                self.teacher_id = TeacherInfo.objects.get(
                    name=self.teacher_name
                ).teacher_id
                # self.save()
            elif self.teacher_id:
                self.teacher_name = TeacherInfo.objects.get(
                    teacher_id=self.teacher_id.teacher_id
                ).name
                # self.save()
            elif not self.teacher_id and self.teacher_name == "":
                print("教师ID或姓名未填写")
        except ObjectDoesNotExist:
            print("教师ID或姓名不存在")

    def save(self, *args, **kwargs):
        self.update_class_name()
        self.update_course_name()
        self.update_teacher_name()
        super(ClassCourse, self).save(*args, **kwargs)

    def __str__(self):
        self.save()
        return self.class_name + "-" + self.course_name


class StudentInfo(models.Model):
    """
    学生信息表
    """

    GENDER_CHOICES = [
        ("男", "男"),
        ("女", "女"),
        ("未知", "未知"),
    ]

    student_id = models.CharField(
        primary_key=True, max_length=20, unique=True, verbose_name="学号"
    )
    name = models.CharField(max_length=20, verbose_name="姓名")
    age = models.IntegerField(verbose_name="年龄", default=0)
    gender = models.CharField(
        max_length=2, verbose_name="性别", choices=GENDER_CHOICES, default="未知"
    )
    id_card = models.CharField(
        max_length=18,
        verbose_name="身份证号",
        unique=True,
        validators=[
            MinLengthValidator(18, message="身份证号长度为18位"),
            MaxLengthValidator(18, message="身份证号长度为18位"),
        ],
    )
    tel = models.CharField(max_length=11, verbose_name="联系电话", default=00000000000)
    class_id = models.ForeignKey(
        ClassInfo, on_delete=models.PROTECT, verbose_name="班级ID", default=None
    )
    class_name = models.CharField(max_length=20, verbose_name="班级名称", default="")
    class_header_id = models.CharField(
        max_length=20, verbose_name="班主任工号", default=""
    )
    class_header = models.CharField(
        max_length=20, verbose_name="班主任姓名", default=""
    )
    course_count = models.IntegerField(verbose_name="课程数量", default=0)
    eval_count = models.IntegerField(verbose_name="评测次数", default=0)
    remain = models.IntegerField(verbose_name="差欠量", default=0)

    class Meta:
        verbose_name_plural = "学生信息"
        verbose_name = "学生信息"
        db_table = "zy_student"

    def update_age_gender(self):
        """
        更新年龄
        """
        if self.id_card:
            try:
                birth = str(self.id_card)[6:14]
                today = timezone.now().date()
                birth_date = timezone.datetime.strptime(birth, "%Y%m%d").date()
                age = (
                    today.year
                    - birth_date.year
                    - ((today.month, today.day) < (birth_date.month, birth_date.day))
                )
                self.gender = "男" if int(self.id_card[-2]) % 2 == 1 else "女"
                self.age = age
            except ValueError:
                return

    def update_course_count(self):
        """
        更新课程数量
        """
        self.course_count = ClassCourse.objects.filter(
            class_id=self.class_id.class_id
        ).count()
        # self.save()

    def update_eval_count(self):
        """
        更新评测次数
        """
        self.eval_count = temp = EvalList.objects.filter(
            student_id=self.student_id,
            eval_date__gte=timezone.now() - timedelta(days=90),
        ).count()
        self.remain = self.course_count - temp
        # self.save()

    def update_class_name(self):
        """
        更新班级名称
        """
        try:
            if self.class_id and self.class_name == "":
                self.class_name = ClassInfo.objects.get(
                    class_id=self.class_id.class_id
                ).class_name
                # self.save()
            elif not self.class_id and self.class_name != "":
                self.class_id = ClassInfo.objects.get(
                    class_name=self.class_name
                ).class_id
                # self.save()
            elif self.class_id:
                self.class_name = ClassInfo.objects.get(
                    class_id=self.class_id.class_id
                ).class_name
                # self.save()
            elif not self.class_id and self.class_name == "":
                print("班级ID或名称未填写")
        except ObjectDoesNotExist:
            print("班级ID或名称不存在")

    def update_class_header(self):
        """
        更新班主任姓名
        """
        try:
            if self.class_id:
                self.class_header_id = ClassInfo.objects.get(
                    class_id=self.class_id.class_id
                ).class_header_id.teacher_id
                self.class_header = ClassInfo.objects.get(
                    class_id=self.class_id.class_id
                ).class_header
                # self.save()
            else:
                print("班级ID未填写")
        except ObjectDoesNotExist:
            print("班级ID不存在")

    def save(self, *args, **kwargs):
        self.update_age_gender()
        self.update_course_count()
        self.update_eval_count()
        self.update_class_name()
        self.update_class_header()
        super(StudentInfo, self).save(*args, **kwargs)

    def __str__(self):
        self.save()
        return self.name


# 下列信号代码已废弃，会导致递归调用
# ##############教师信息表更新信号#############
# @receiver(post_save, sender=ClassCourse)
# @receiver(post_delete, sender=ClassCourse)
# def update_teacher_course_count(sender, instance, **kwargs):
#     """
#     课程数量更新信号
#     """
#     for teacher in TeacherInfo.objects.all():
#         teacher.save()


# @receiver(post_save, sender=EvalList)
# @receiver(post_delete, sender=EvalList)
# def update_teacher_eval_count(sender, instance, **kwargs):
#     """
#     被评测量更新信号
#     """
#     for teacher in TeacherInfo.objects.filter(teacher_id=instance.teacher_id):
#         teacher.save()


# ##############班级信息表更新信号#############
# @receiver(post_save, sender=ClassCourse)
# @receiver(post_delete, sender=ClassCourse)
# def update_class_course_count(sender, instance, **kwargs):
#     """
#     ClassCourse表数据更新时，自动调用ClassInfo模型的save方法进行课程统计course_count数据更新
#     """
#     for class_ in ClassInfo.objects.filter(class_id=instance.class_id):
#         class_.save()


# @receiver(post_save, sender=StudentInfo)
# @receiver(post_delete, sender=StudentInfo)
# def update_class_student_count(sender, instance, **kwargs):
#     """
#     StudentInfo表数据更新时，自动调用ClassInfo模型的save方法进行学生数量统计student_count数据更新
#     """
#     for class_ in ClassInfo.objects.filter(class_id=instance.class_id):
#         class_.save()


# @receiver(post_save, sender=TeacherInfo)
# @receiver(post_delete, sender=TeacherInfo)
# def update_class_header(sender, instance, **kwargs):
#     """
#     TeacherInfo表数据更新时，自动调用ClassInfo模型的save方法进行相关字段更新
#     """
#     for class_ in ClassInfo.objects.filter(class_header_id=instance.teacher_id):
#         class_.save()


# @receiver(post_save, sender=EvalList)
# @receiver(post_delete, sender=EvalList)
# def update_class_eval_count(sender, instance, **kwargs):
#     """
#     调用ClassInfo模型的save方法进行调查问卷量eval_count数据统计更新
#     """
#     for class_ in ClassInfo.objects.filter(class_id=instance.class_id):
#         class_.save()


# ##############班级课程表更新信号#############
# @receiver(post_save, sender=ClassInfo)
# @receiver(post_delete, sender=ClassInfo)
# def update_class_course_class_name(sender, instance, **kwargs):
#     """
#     调用ClassCourse模型的save方法进行相关字段更新
#     """
#     for class_course in ClassCourse.objects.filter(class_id=instance.class_id):
#         class_course.save()


# @receiver(post_save, sender=CourseInfo)
# @receiver(post_delete, sender=CourseInfo)
# def update_class_course_course_name(sender, instance, **kwargs):
#     """
#     调用ClassCourse模型的save方法进行相关字段更新
#     """
#     for class_course in ClassCourse.objects.filter(course_id=instance.course_id):
#         class_course.save()


# @receiver(post_save, sender=TeacherInfo)
# @receiver(post_delete, sender=TeacherInfo)
# def update_class_course_teacher_name(sender, instance, **kwargs):
#     """
#     调用ClassCourse模型的save方法进行相关字段更新
#     """
#     for class_course in ClassCourse.objects.filter(teacher_id=instance.teacher_id):
#         class_course.save()


# ##############学生信息表更新信号#############
# @receiver(post_save, sender=ClassCourse)
# @receiver(post_delete, sender=ClassCourse)
# def update_student_info(sender, instance, **kwargs):
#     """
#     在ClassCourse模型的新建、更新或删除数据时，自动调用StudentInfo模型的save方法更新course_count统计
#     """
#     for student in StudentInfo.objects.filter(class_id=instance.class_id):
#         student.save()


# @receiver(post_save, sender=EvalList)
# @receiver(post_delete, sender=EvalList)
# def update_student_eval_count(sender, instance, **kwargs):
#     """
#     在EvalList模型的新建、更新或删除数据时，自动调用StudentInfo模型的save方法更新eval_count统计
#     """
#     for student in StudentInfo.objects.filter(student_id=instance.student_id):
#         student.save()


# @receiver(post_save, sender=ClassInfo)
# @receiver(post_delete, sender=ClassInfo)
# def update_student_class_info(sender, instance, **kwargs):
#     """
#     在ClassInfo模型的新建、更新或删除数据时，自动调用StudentInfo模型的save方法更新班级及教师信息
#     """
#     for student in StudentInfo.objects.filter(class_id=instance.class_id):
#         student.save()
